@file:Suppress("ClassName")

package io.github.sds100.keymapper.data.migration

import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.SupportSQLiteQueryBuilder
import com.github.salomonbrys.kotson.fromJson
import com.github.salomonbrys.kotson.registerTypeAdapter
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import io.github.sds100.keymapper.common.utils.hasFlag
import io.github.sds100.keymapper.common.utils.minusFlag
import io.github.sds100.keymapper.common.utils.withFlag
import io.github.sds100.keymapper.data.entities.KeyEventTriggerKeyEntity
import io.github.sds100.keymapper.data.entities.TriggerEntity
import io.github.sds100.keymapper.data.entities.TriggerKeyEntity

object Migration6To7 {

    private const val TRIGGER_FLAG_DONT_OVERRIDE_DEFAULT_ACTION = 8

    fun migrate(database: SupportSQLiteDatabase) = database.apply {
        val query = SupportSQLiteQueryBuilder
            .builder("keymaps")
            .columns(arrayOf("id", "trigger", "flags"))
            .create()

        query(query).apply {
            val gson = GsonBuilder()
                .registerTypeAdapter(TriggerEntity.DESERIALIZER)
                .registerTypeAdapter(TriggerKeyEntity.DESERIALIZER)
                .create()

            while (moveToNext()) {
                val idColumnIndex = getColumnIndex("id")
                val id = getInt(idColumnIndex)

                val triggerColumnIndex = getColumnIndex("trigger")

                val trigger = gson.fromJson<TriggerEntity>(getString(triggerColumnIndex))

                val newTriggerKeys = trigger.keys
                    .mapNotNull { it as? KeyEventTriggerKeyEntity }
                    .map { key ->
                        if (trigger.flags.hasFlag(TRIGGER_FLAG_DONT_OVERRIDE_DEFAULT_ACTION)) {
                            key.copy(
                                flags = key.flags.withFlag(
                                    KeyEventTriggerKeyEntity.FLAG_DO_NOT_CONSUME_KEY_EVENT,
                                ),
                            )
                        } else {
                            key
                        }
                    }

                val newTriggerFlags = trigger.flags.minusFlag(
                    TRIGGER_FLAG_DONT_OVERRIDE_DEFAULT_ACTION,
                )
                val newTrigger = trigger.copy(keys = newTriggerKeys, flags = newTriggerFlags)

                execSQL("UPDATE keymaps SET trigger='${newTrigger.json}', flags=0 WHERE id=$id")
            }

            close()
        }
    }

    val Any.json: String
        get() = Gson().toJson(this)
}
